
#include "zcompositor.h"

#include "tgt/textureunit.h"

#include <vector>
#include <windows.h>
#include <math.h>

using tgt::TextureUnit;


namespace voreen {

ZCompositor::ZCompositor()
    : ImageProcessor("zcompositor")
	, compositingModeProp_("blendMode", "Blend mode", Processor::INVALID_PROGRAM)
	, kernelSizeProp_("kernelSize", "Gaussian blur kernel size: ", 0, 0, 25)
	, patternWidthProp_("patternWidth", "Pattern width: ", 20, 1, 500)
	, offsetX_("offsetX", "Pattern horizontal offset: ", 0, -250, 250)
	, offsetY_("offsetY", "Pattern vertical offset: ", 0, -250, 250)
	, overlayThreshold_("overlayThreshold","Overlay threshold: ", 0.5f, 0.0f, 1.0f, Processor::VALID)
    , inport0_(Port::INPORT, "image.inport0")
    , inport1_(Port::INPORT, "image.inport1")
    , outport_(Port::OUTPORT, "image.outport")
{
	compositingModeProp_.addOption("gauss_1", "Gaussian blur of field 1", "GAUSSIAN_1");
	compositingModeProp_.addOption("gauss_2", "Gaussian blur of field 2", "GAUSSIAN_2");
	compositingModeProp_.addOption("grad_1", "Gradient of field 1", "GRADIENT_1");
	compositingModeProp_.addOption("grad_2", "Gradient of field 2", "GRADIENT_2");
	compositingModeProp_.addOption("bumpmap_1", "Bumpmap field 1 over field 2", "BUMPMAP_1");
	compositingModeProp_.addOption("bumpmap_2", "Bumpmap field 2 over field 1", "BUMPMAP_2");
	compositingModeProp_.addOption("msk_checker", "Pattern masking: checkerboard", "MSK_CHECKER");
	compositingModeProp_.addOption("overlay_1", "Overlay field 1 over field 2", "OVERLAY_1");
    compositingModeProp_.onChange(CallMemberAction<ZCompositor>(this, &ZCompositor::compositingModeChanged));

    addProperty(compositingModeProp_);
    addProperty(kernelSizeProp_);
    addProperty(patternWidthProp_);
    addProperty(offsetX_);
    addProperty(offsetY_);
    addProperty(overlayThreshold_);

    addPort(inport0_);
    addPort(inport1_);
    addPort(outport_);
}

ZCompositor::~ZCompositor() {}

void ZCompositor::initialize() throw (tgt::Exception){
    //call parent's initialize method
    ImageProcessor::initialize();

    //Hide properties that should be invisible at beginning
    compositingModeChanged();

    copyShader_ = ShdrMgr.loadSeparate("passthrough.vert", "copyimage.frag", ImageProcessor::generateHeader(), false);
}

void ZCompositor::deinitialize() throw (tgt::Exception) {
    ImageProcessor::deinitialize();
    ShdrMgr.dispose(copyShader_);
    copyShader_ = 0;
}

bool ZCompositor::isReady() const {
    bool ready = inport0_.isReady();
    return ready;
}

void ZCompositor::process() {
    if(!inport1_.isReady()){ return; } // how about inport0_?
    if (getInvalidationLevel() >= Processor::INVALID_PROGRAM){ compile(); }

    outport_.activateTarget();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDepthFunc(GL_ALWAYS);

    TextureUnit colorUnit, depthUnit;
    TextureUnit colorUnit1, depthUnit1;
    inport0_.bindTextures(colorUnit.getEnum(), depthUnit.getEnum());
    inport1_.bindTextures(colorUnit1.getEnum(), depthUnit1.getEnum());

    // initialize shader
    program_->activate();
    setGlobalShaderParameters(program_);

	// set both textures on the shader
    program_->setUniform("colorTex0_", colorUnit.getUnitNumber());
    program_->setUniform("depthTex0_", depthUnit.getUnitNumber());
    inport0_.setTextureParameters(program_, "textureParameters0_");
    program_->setUniform("colorTex1_", colorUnit1.getUnitNumber());
    program_->setUniform("depthTex1_", depthUnit1.getUnitNumber());
    inport1_.setTextureParameters(program_, "textureParameters1_");

    program_->setUniform("kernelSize_", kernelSizeProp_.get());

    if (compositingModeProp_.get() == "msk_checker") {
		program_->setUniform("patternWidth_", patternWidthProp_.get());
		program_->setUniform("offsetX_", offsetX_.get());
		program_->setUniform("offsetY_", offsetY_.get());
	}
    if (compositingModeProp_.get() == "overlay_1") {
    	std::cout << "\n\noverlay: " << overlayThreshold_.get() << "\n\n";
		program_->setUniform("overlayThreshold_", overlayThreshold_.get());
    }

    renderQuad();

    glDepthFunc(GL_LESS);

    program_->deactivate();
    outport_.deactivateTarget();
    TextureUnit::setZeroUnit();
    LGL_ERROR;
}

std::string ZCompositor::generateHeader(const tgt::GpuCapabilities::GlVersion* version) {
    std::string header = ImageProcessor::generateHeader(version);
    header += "#define " + compositingModeProp_.getValue() + "\n";
    return header;
}

void ZCompositor::compile() {
    if (program_){ program_->setHeaders(generateHeader()); }
    ImageProcessor::compile();
}

void ZCompositor::compositingModeChanged() {
    patternWidthProp_.setVisible(compositingModeProp_.get() == "msk_checker");
    offsetX_.setVisible(compositingModeProp_.get() == "msk_checker");
    offsetY_.setVisible(compositingModeProp_.get() == "msk_checker");
    overlayThreshold_.setVisible(compositingModeProp_.get() == "overlay_1");
}

} // voreen namespace
